/**
 * test-client-simple.js - 简化版测试客户端
 * 用于连接到热键检测服务器并测试热键检测功能
 * 没有使用随机数，便于理解和测试
 */
const net = require('net');

// 配置
const SERVER_HOST = 'localhost';
const SERVER_PORT = 11111;
const APP_NAME = 'app2'; // 应用名称

// 接收缓冲区
let dataBuffer = '';

// 测试模式
const TEST_MODES = {
  FIXED_KEY: 'fixed_key',      // 固定键测试：发送同一个键多次
  BURST: 'burst',              // 突发测试：快速发送大量计数
  SEQUENTIAL: 'sequential'     // 顺序测试：按顺序发送不同键
};

/**
 * 连接到热键检测服务器
 */
function connectToHotKeyServer() {
  console.log(`正在连接到热键检测服务器 ${SERVER_HOST}:${SERVER_PORT}...`);
  
  // 创建客户端socket
  const client = net.createConnection({
    host: SERVER_HOST,
    port: SERVER_PORT
  });
  
  // 设置编码
  client.setEncoding('utf8');
  
  // 连接成功事件
  client.on('connect', () => {
    console.log('连接成功！');
    
    // 发送注册消息
    registerApp(client, APP_NAME);
  });
  
  // 接收数据事件
  client.on('data', (data) => {
    try {
      // 将新数据添加到缓冲区
      dataBuffer += data;
      
      // 尝试解析JSON，支持可能的多个JSON对象处理
      let startPos = 0;
      let endPos = 0;
      
      while ((startPos = dataBuffer.indexOf('{', endPos)) >= 0) {
        // 找到下一个左括号的位置
        endPos = findJsonEnd(dataBuffer, startPos);
        
        if (endPos > 0) {
          try {
            // 提取并解析JSON
            const jsonStr = dataBuffer.substring(startPos, endPos + 1);
            const message = JSON.parse(jsonStr);
            
            // 处理消息
            handleMessage(message);
          } catch (parseErr) {
            // 解析该部分失败，继续尝试下一部分
            console.error('解析JSON失败:', parseErr);
          }
        } else {
          // 没有找到完整的JSON对象，等待更多数据
          break;
        }
      }
      
      // 如果有成功解析的数据，清理缓冲区
      if (endPos > 0) {
        dataBuffer = dataBuffer.substring(endPos);
      }
    } catch (err) {
      console.error('处理接收数据时出错:', err);
    }
  });
  
// 辅助函数：找到一个完整JSON对象的结束位置
function findJsonEnd(jsonString, startPos) {
  let depth = 0;
  let inString = false;
  let escape = false;
  
  for (let i = startPos; i < jsonString.length; i++) {
    const char = jsonString[i];
    
    if (escape) {
      escape = false;
      continue;
    }
    
    if (inString) {
      if (char === '\\') {
        escape = true;
      } else if (char === '"') {
        inString = false;
      }
      continue;
    }
    
    if (char === '"') {
      inString = true;
    } else if (char === '{') {
      depth++;
    } else if (char === '}') {
      depth--;
      if (depth === 0) {
        return i; // 返回右括号的位置
      }
    }
  }
  
  return -1; // 未找到完整的JSON
}
  
  // 错误事件
  client.on('error', (err) => {
    console.error('连接错误:', err);
  });
  
  // 关闭事件
  client.on('close', () => {
    console.log('连接已关闭，5秒后重新连接');
    setTimeout(connectToHotKeyServer, 5000);
  });
  
  return client;
}

/**
 * 处理接收到的消息
 * @param {Object} message - 解析后的消息对象
 */
function handleMessage(message) {
  // 确保消息有类型
  if (!message || !message.type) {
    console.error('收到无效消息:', message);
    return;
  }
  
  try {
    switch (message.type) {
      case 'welcome':
        console.log(`收到欢迎消息: ${message.message} (服务器ID: ${message.serverId})`);
        break;
      case 'register_ack':
        console.log(`应用注册${message.success ? '成功' : '失败'}`);
        break;
      case 'hotkey':
        handleHotKey(message.data);
        break;
      case 'remove_hotkey':
        handleRemoveHotKey(message.data);
        break;
      case 'key_event_ack':
        console.log(`键事件已确认接收: ${message.key}`);
        break;
      default:
        console.log('收到未知类型消息:', message);
    }
  } catch (err) {
    console.error('处理消息时出错:', err, '消息内容:', message);
  }
}

/**
 * 注册应用
 * @param {net.Socket} client - 客户端socket
 * @param {string} appName - 应用名称
 */
function registerApp(client, appName) {
  console.log(`注册应用: ${appName}`);
  
  const message = {
    type: 'register',
    appName
  };
  
  client.write(JSON.stringify(message));
}

/**
 * 处理热键
 * @param {Object} hotKeyModel - 热键模型
 */
function handleHotKey(hotKeyModel) {
  console.log(`\n【热键触发】应用:${hotKeyModel.appName}, 类型:${hotKeyModel.keyType}, 键:${hotKeyModel.key}`);
  console.log('热键详情:', JSON.stringify(hotKeyModel, null, 2));
  console.log('热键已缓存到本地\n');
}

/**
 * 处理热键删除
 * @param {Object} hotKeyModel - 热键模型
 */
function handleRemoveHotKey(hotKeyModel) {
  console.log(`\n【热键移除】应用:${hotKeyModel.appName}, 类型:${hotKeyModel.keyType}, 键:${hotKeyModel.key}`);
  console.log('热键已从本地缓存移除\n');
}

/**
 * 发送单个键事件
 * @param {net.Socket} client - 客户端socket
 * @param {string} key - 键
 * @param {string} keyType - 键类型
 * @param {number} count - 计数
 */
function sendKeyEvent(client, key, keyType, count) {
  const keyEvent = {
    type: 'key_event',
    appName: APP_NAME,
    keyType: keyType,
    key: key,
    count: count
  };
  
  console.log(`发送键事件: ${key}，类型: ${keyType}，计数: ${count}`);
  client.write(JSON.stringify(keyEvent));
}

/**
 * 固定键测试：发送同一个键多次
 * @param {net.Socket} client - 客户端socket
 */
function runFixedKeyTest(client) {
  console.log('\n===== 开始固定键测试 =====');
  console.log('将连续发送同一个键10次，每次计数为1');
  
  const key = 'testkey1';
  const keyType = 'hash';  // app2配置为hash类型
  const count = 1;
  let sentCount = 0;
  
  // 每500毫秒发送一次，连续发10次
  // 类似Java版本的设计思想，不要求每条消息都必须确认
  const interval = setInterval(() => {
    sendKeyEvent(client, key, keyType, count);
    sentCount++;
    
    // 发送10次后停止
    if (sentCount >= 10) {
      clearInterval(interval);
      console.log('固定键测试完成，共发送10次');
      console.log('如果在5秒窗口内累积超过10次计数，应触发热键');
    }
  }, 500);
}

/**
 * 突发测试：快速发送大量计数
 * @param {net.Socket} client - 客户端socket
 */
function runBurstTest(client) {
  console.log('\n===== 开始突发测试 =====');
  console.log('将发送一个计数值为20的键事件');
  
  // 发送一个计数较大的键事件
  sendKeyEvent(client, 'burstkey', 'hash', 20);
  
  console.log('突发测试完成');
  console.log('由于单次计数超过app2的阈值10，应立即触发热键');
}

/**
 * 顺序测试：按顺序发送不同键
 * @param {net.Socket} client - 客户端socket
 */
function runSequentialTest(client) {
  console.log('\n===== 开始顺序测试 =====');
  console.log('将按顺序发送3个不同的键');
  
  const keys = ['user1', 'product2', 'order3'];
  const keyType = 'hash';
  let index = 0;
  
  // 每1秒发送一个不同的键
  const interval = setInterval(() => {
    if (index < keys.length) {
      const key = keys[index];
      // 每个键发送5个计数
      sendKeyEvent(client, key, keyType, 5);
      index++;
    } else {
      clearInterval(interval);
      console.log('顺序测试完成，共发送3个不同的键');
      console.log('单个键的计数未超过阈值，不应触发热键');
      
      // 测试完成后，发送一个相同键的高计数事件
      setTimeout(() => {
        console.log('\n发送一个计数为15的键事件 (user1)');
        sendKeyEvent(client, 'user1', keyType, 15);
        console.log('由于这个键已经累积了5个计数，加上新的15个计数，超过了阈值，应触发热键');
      }, 1000);
    }
  }, 1000);
}

/**
 * 启动测试客户端
 */
function startClient() {
  console.log('启动简化版热键测试客户端');
  
  // 连接到热键服务器
  const client = connectToHotKeyServer();
  
  // 处理命令行参数
  const args = process.argv.slice(2);
  const testMode = args[0] || TEST_MODES.FIXED_KEY;
  
  // 等待连接和注册成功后，开始测试
  setTimeout(() => {
    switch (testMode) {
      case TEST_MODES.BURST:
        runBurstTest(client);
        break;
      case TEST_MODES.SEQUENTIAL:
        runSequentialTest(client);
        break;
      case TEST_MODES.FIXED_KEY:
      default:
        runFixedKeyTest(client);
        break;
    }
    
    // 显示使用方法
    console.log('\n===== 使用说明 =====');
    console.log('可用的测试模式:');
    console.log('- fixed_key: 发送同一个键多次 (默认)');
    console.log('- burst: 发送一个大计数值的键事件');
    console.log('- sequential: 按顺序发送不同的键');
    console.log('\n使用方式: node test-client-simple.js [测试模式]');
    console.log('例如: node test-client-simple.js burst');
  }, 2000);
  
  // 优雅退出
  process.on('SIGINT', () => {
    console.log('客户端关闭中...');
    client.end();
    process.exit(0);
  });
}

// 启动客户端
startClient();
